home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / FTPSERV.C < prev    next >
C/C++ Source or Header  |  1997-09-14  |  39KB  |  1,470 lines

  1. /* Internet FTP Server server machine - see RFC 959
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by KO4KS
  5.  */
  6. #include "global.h"
  7. #include "ctype.h"
  8. #include "commands.h"
  9. #ifdef UNIX
  10. #include <time.h>
  11. #include <sys/stat.h>
  12. #include <fcntl.h>
  13. #endif
  14. #include "mbuf.h"
  15. #include "socket.h"
  16. #include "ftp.h"
  17. #include "ftpserv.h"
  18. #include "dirutil.h"
  19. #include "files.h"
  20. #include "session.h"
  21. #include "smtp.h"
  22. #ifdef CALLSERVER
  23. /* CD-ROM code by Fred Peachman KB7YW */
  24. extern char *CDROM;        /* buckbook.c: defines CDROM drive letter e.g. "s:"  */
  25.  
  26. #endif /* #ifdef CALLSERVER  */
  27. #ifdef LZW
  28. #include "lzw.h"
  29. #endif
  30. #include "x.h"
  31.  
  32.  
  33. #if !defined(_lint)
  34. static char rcsid[] OPTIONAL = "$Id: ftpserv.c,v 1.31 1997/09/14 14:37:46 root Exp root $";
  35. #endif
  36.  
  37. #ifdef UNIX
  38. int ftpsecuritycheck (char *filename, int perms, int mode);
  39. extern long ACCESSgid, ACCESSuid;
  40. extern long CREATEgid, CREATEuid;
  41. extern short CREATEmask;
  42. extern int CREATEsecure;
  43.  
  44. #ifndef R_OK
  45. #define R_OK 4
  46. #endif
  47. #ifndef W_OK
  48. #define W_OK 2
  49. #endif
  50. #endif
  51.  
  52. static int isanonymous (char *name);
  53. static void ftpserv (int s, void *unused, void *p);
  54. static int pport (struct sockaddr_in *sock, char *arg);
  55. static void ftplogin (struct ftpserv *ftp, char *pass);
  56. static int sendit (struct ftpserv *ftp, const char *command, char *file);
  57. static int recvit (struct ftpserv *ftp, const char *command, char *file);
  58. static void sendmsgfile (int s, int num, char *buf, int size, FILE * fp);
  59. static void SendPasv (int s, struct sockaddr_in *sock);
  60. extern char *addroot (const char *root, const char *name);
  61. extern char *defpath (struct cur_dirs *curdirs, char *path);
  62.  
  63.  
  64. /* Command table */
  65. static const char *commands[] =
  66. {
  67.     "user",
  68.     "acct",
  69.     "pass",
  70.     "type",
  71.     "list",
  72.     "cwd",
  73.     "dele",
  74.     "help",
  75.     "quit",
  76.     "retr",
  77.     "stor",
  78.     "port",
  79.     "nlst",
  80.     "pwd",
  81.     "xpwd",            /* For compatibility with 4.2BSD */
  82.     "mkd ",
  83.     "xmkd",            /* For compatibility with 4.2BSD */
  84.     "xrmd",            /* For compatibility with 4.2BSD */
  85.     "rmd ",
  86.     "stru",
  87.     "mode",
  88.     "syst",
  89.     "xmd5",
  90.     "rsme",            /* Added by IW0CNB, for resuming interrupted trasnfers */
  91.     "rput",
  92.     "rnfr",
  93.     "rnto",
  94.     "cdup",
  95.     "appe",
  96.     "noop",            /* for OS/2 compatibility */
  97.     "size",
  98.     "pasv",            /*PASV mod by G4IDE*/
  99. #ifdef LZW
  100.     "xlzw",
  101. #endif
  102.     NULLCHAR
  103. };
  104.  
  105.  
  106. #if 0
  107. static char challenge[] = "399 PASS challenge : %016lx\n";
  108. static char lowmem[] = "421 System overloaded, try again later\n";
  109. #endif
  110.  
  111. #ifdef CATALOG
  112. #include "catalog.h"
  113.  
  114. #define CAT ftpserv_catalog
  115.  
  116. #define banner        __STR(0)
  117. #define banner1        __STR(1)
  118. #define banner2        __STR(2)
  119. #define badcmd        __STR(3)
  120. #define binwarn        __STR(4)
  121. #define unsupp        __STR(5)
  122. #define givepass    __STR(6)
  123. #define anonokay    __STR(7)
  124. #define logged        __STR(8)
  125. #define loggeda        __STR(9)
  126. #define typeok        __STR(10)
  127. #define only8        __STR(11)
  128. #define deleok        __STR(12)
  129. #define mkdok        __STR(13)
  130. #define delefail    __STR(14)
  131. #define pwdmsg        __STR(15)
  132. #define badtype        __STR(16)
  133. #define badport        __STR(17)
  134. #define unimp        __STR(18)
  135. #define bye        __STR(19)
  136. #define nodir        __STR(20)
  137. #define cantopen    __STR(21)
  138. #define sending        __STR(22)
  139. #define cantmake    __STR(23)
  140. #define writerr        __STR(24)
  141. #define portok        __STR(25)
  142. #define rxok        __STR(26)
  143. #define txok        __STR(27)
  144. #define noperm        __STR(28)
  145. #define noconn        __STR(29)
  146. #define badcheck    __STR(30)
  147. #define notlog        __STR(31)
  148. #define userfirst    __STR(32)
  149. #define okay        __STR(33)
  150. #define syst        __STR(34)
  151. #define pendingto    __STR(35)
  152. #define badseq        __STR(36)
  153. #define norename    __STR(37)
  154. #define help        __STR(38)
  155. #define filesize    __STR(39)
  156. #define notaplain    __STR(40)
  157. #define nosuchfile    __STR(41)
  158. #define pasvmodestr    __STR(42)
  159. #else
  160.  
  161. /* Response messages */
  162. static char banner[] = "220 %s, KA9Q-NOS FTP version %s\n";
  163. static char banner1[] = "230- Ready on %s";
  164. static char banner2[] = "230- Total active FTP sessions at %s: %d out of %d maximum\n";
  165. static char badcmd[] = "500 Unknown command\n";
  166. static char binwarn[] = "150- Warning: type is ASCII and %s appears to be binary\n";
  167. static char unsupp[] = "500 Unsupported command or option\n";
  168. static char givepass[] = "331 Enter PASS command\n";
  169. static char anonokay[] = "331 Anonymous access, give email address as password\n";
  170. static char logged[] = "230 Logged in\n";
  171. static char loggeda[] = "230 Logged in as anonymous, restrictions apply\n";
  172. static char typeok[] = "200 Type %s OK\n";
  173. static char only8[] = "501 Only logical bytesize 8 supported\n";
  174. static char deleok[] = "250 File deleted\n";
  175. static char mkdok[] = "200 MKD ok\n";
  176. static char delefail[] = "550 Delete failed: %s\n";
  177. static char pwdmsg[] = "257 \"%s\" is current directory\n";
  178. static char badtype[] = "501 Unknown type \"%s\"\n";
  179. static char badport[] = "501 Bad port syntax\n";
  180. static char unimp[] = "502 Command not yet implemented\n";
  181. static char bye[] = "221 Goodbye!\n";
  182. static char nodir[] = "553 Can't read directory \"%s\": %s\n";
  183. static char cantopen[] = "550 Can't read file \"%s\": %s\n";
  184. static char sending[] = "150 Opening data connection for %s %s %s\n";    /*N1BEE*/
  185. static char cantmake[] = "553 Can't create \"%s\": %s\n";
  186. static char writerr[] = "552 Write error: %s\n";
  187. static char portok[] = "200 Port command okay\n";
  188. static char rxok[] = "226 File received OK\n";
  189. static char txok[] = "226 File sent OK\n";
  190. static char noperm[] = "550 Permission denied\n";
  191. static char noconn[] = "425 Data connection reset\n";
  192. static char badcheck[] = "425 Bad checksum\n";
  193. static char notlog[] = "530 Please log in with USER and PASS\n";
  194. static char userfirst[] = "503 Login with USER first.\n";
  195. static char okay[] = "200 Ok\n";
  196. static char syst[] = "215 %s Type: L%d Version: %s\n";
  197. static char pendingto[] = "350 Rename awaiting new name.\n";
  198. static char badseq[] = "503 No prior RNFR received - RNTO ignored\n";
  199. static char norename[] = "550 Can't rename: %s\n";
  200. static char help[] = "214-The following commands are recognized.\n";
  201. static char filesize[] = "213 %lu\n";
  202. static char notaplain[] = "550 %s: not a plain file\n";
  203. static char nosuchfile[] = "550 %s: No such file\n";
  204. static char pasvmodestr[] = "227 Entering Passive Mode. %u,%u,%u,%u,%u,%u\n";
  205. #endif
  206.  
  207.  
  208. int Sftp = -1;            /* Prototype socket for service */
  209. int FtpUsers = 0;
  210. static int FtpMaxUsers = 255;
  211.  
  212. #ifdef FTPTDISC
  213. static int32 Ftptdiscinit = 0;
  214.  
  215.  
  216.  
  217. /* Set ftp redundancy timer */
  218. int
  219. doftptdisc (int argc, char *argv[], void *p OPTIONAL)
  220. {
  221.     return setlong (&Ftptdiscinit, "Ftp redundancy timer (sec)", argc, argv);
  222. }
  223.  
  224.  
  225.  
  226. static void
  227. ftp_redundant (struct ftpserv *ftp)
  228. {
  229.     /* Clean up */
  230.     (void) shutdown (ftp->control, 2);
  231.     close_s (ftp->control);
  232.     if (ftp->data != -1) {
  233.         (void) shutdown (ftp->data, 2);
  234.         close_s (ftp->data);
  235.         ftp->data = -1;
  236.     }
  237.     return;
  238. }
  239. #endif
  240.  
  241.  
  242.  
  243. /* Set ftp Maximum number of connections */
  244. int
  245. doftpmaxclients (int argc, char *argv[], void *p OPTIONAL)
  246. {
  247.     return setint (&FtpMaxUsers, "Maximum Ftp incoming clients", argc, argv);
  248. }
  249.  
  250.  
  251.  
  252. /* Start up FTP service */
  253. int
  254. ftpstart (int argc, char *argv[], void *p OPTIONAL)
  255. {
  256.     return (installserver (argc, argv, &Sftp, "FTP listener", IPPORT_FTP,
  257.         INADDR_ANY, "ftpserv", ftpserv, 2048, NULL));
  258. }
  259.  
  260.  
  261.  
  262. static void 
  263. sendmsgfile (int s, int num, char *buf, int size, FILE *fp)
  264. {
  265.  
  266.     while (fgets (buf, size, fp)) {
  267.         rip (buf);
  268.         usprintf (s, "%d- %s\n", num, buf);
  269.     }
  270. }
  271.  
  272.  
  273.  
  274. static int
  275. isanonymous (char *name)
  276. {
  277. FILE *fp, *fpsave = NULLFILE;
  278. int retval = 1;
  279. char buf[128], *cp;
  280.  
  281.     if ((fp = fopen (Userfile, READ_TEXT)) != NULLFILE) {
  282.         for ( ; ; ) {
  283.             if (fgets (buf, 128, fp) == NULLCHAR) {
  284.                 if (fpsave) {
  285.                     (void) fclose (fp);
  286.                     fp = fpsave;
  287.                     fpsave = NULLFILE;
  288.                     continue;
  289.                 }
  290.                 break;
  291.             }
  292.             if (!strnicmp (buf, "#include", 8)) {
  293.                 rip (buf);
  294.                 cp = skipwhite (&buf[8]);
  295.                 fpsave = fp;
  296.                 if ((fp = fopen (cp, READ_TEXT)) == NULLFILE) {
  297.                     fp = fpsave;
  298.                     fpsave = NULLFILE;
  299.                 }
  300.                 continue;
  301.             }
  302.             if ((cp = strpbrk (buf, " \t")) == NULLCHAR)
  303.                 /* Bogus entry */
  304.                 continue;
  305.             *cp++ = '\0';
  306.  
  307.             if (!stricmp (name, buf)) {
  308.                 retval = 0;
  309.                 break;    /* Found user */
  310.             }
  311.         }
  312.         if (fpsave)
  313.             (void) fclose (fpsave);
  314.         (void) fclose (fp);
  315.     }
  316.     return (retval);
  317. }
  318.  
  319.  
  320.  
  321. static void
  322. ftpserv (
  323. int s,                /* Socket with user connection */
  324. void *unused OPTIONAL,
  325. void *p OPTIONAL
  326. ) {
  327. struct ftpserv ftp;
  328. char const **cmdp, *cp, *mode = NULLCHAR;
  329. char buf[512], *arg, *file, *cp2;
  330. time_t t;
  331. int cnt, i;
  332. struct sockaddr_in thesocket;
  333. struct cur_dirs dirs;
  334. char *rnfrom = NULLCHAR;
  335. FILE *fpm;
  336. struct sockaddr_in lsocket;    /*PASV mod*/
  337. struct sockaddr_in lcsocket;
  338. #if 0
  339. struct stat cwdstat;
  340. char *cp1;
  341. #endif
  342.  
  343.     (void) sockmode (s, SOCK_ASCII);
  344.     memset ((char *) &ftp, 0, sizeof (ftp));    /* Start with clear slate */
  345.     ftp.data = -1;
  346.  
  347.     (void) sockowner (s, Curproc);    /* We own it now */
  348.     ftp.control = s;
  349.     /* Set default data port */
  350.     i = SOCKSIZE;
  351.     if (getpeername (s, (char *) &thesocket, &i) != -1)    {
  352.         thesocket.sin_port = IPPORT_FTPD;
  353.         ASSIGN (ftp.port, thesocket);
  354.     }
  355.  
  356.     if (++FtpUsers > FtpMaxUsers) {
  357.         usprintf (s, "\n200- Sorry, too many FTP users at %s this time. Try again later!\n", Hostname);
  358.         FtpUsers--;
  359.         return;
  360.     }
  361.  
  362. #ifdef FTPTDISC
  363.     /* Set the timeout timer - WG7J */
  364.     set_timer (&ftp.tdisc, Ftptdiscinit * 1000L);
  365.     ftp.tdisc.func = (void (*)(void *)) ftp_redundant;
  366.     ftp.tdisc.arg = &ftp;
  367.     start_timer (&ftp.tdisc);
  368. #endif
  369.  
  370. #ifdef STATS_USE
  371.     STATS_adduse (1);
  372. #endif
  373. #ifdef XSERVER
  374.     xnotify (X_FTP);
  375. #endif
  376.     log (s, "open FTP");
  377.     strcpy (buf, ETCdir);
  378.     if ((fpm = fopen (strcat (buf, "/banner.ftp"), "r")) != NULL) {
  379.         sendmsgfile (s, 220, buf, sizeof (buf), fpm);
  380.         (void) fclose (fpm);
  381.     }
  382.     usprintf (s, banner, Hostname, Version);
  383.     (void) init_dirs (&dirs);
  384.     ftp.curdirs = &dirs;
  385.     (void) time (&t);
  386.     cp = ctime (&t);
  387. #if 0
  388.     if ((cp1 = strchr (cp, '\n')) != NULLCHAR)
  389.         *cp1 = '\0';
  390. #endif
  391.  
  392.     /* Command interpreting loop */
  393. loop:
  394.     if ((cnt = recvline (s, (unsigned char *) buf, sizeof (buf))) == -1) {
  395.         /* He closed on us */
  396.         goto finish;
  397.     }
  398. #ifdef FTPTDISC
  399.     /* Reset the timeout timer - WG7J */
  400.     start_timer (&ftp.tdisc);
  401. #endif
  402.     if (cnt == 0) {
  403.         /* Can't be a legal FTP command */
  404.         usprintf (ftp.control, badcmd);
  405.         goto loop;
  406.     }
  407.     rip (buf);
  408.     /* Translate first word to lower case */
  409.     for (cp2 = buf; *cp2 != ' ' && *cp2 != '\0'; cp2++)
  410.         *cp2 = (char) tolower (*cp2);
  411.     /* Find command in table; if not present, return syntax error */
  412.     for (cmdp = commands; *cmdp != NULLCHAR; cmdp++)
  413.         if (strnicmp (*cmdp, buf, strlen (*cmdp)) == 0)
  414.             break;
  415.     if (*cmdp == NULLCHAR) {
  416.         usprintf (ftp.control, badcmd);
  417.         goto loop;
  418.     }
  419. #if 0
  420.     tcmdprintf ("Command received was: '%s'\n", buf);
  421. #endif
  422.     /* Allow only USER, PASS and QUIT before logging in */
  423.     if (ftp.path == NULLCHAR) {
  424.         switch (cmdp - commands) {
  425.             case USER_CMD:
  426.             case PASS_CMD:
  427.             case QUIT_CMD:
  428.                 break;
  429.             default:
  430.                 usprintf (ftp.control, notlog);
  431.                 goto loop;
  432.         }
  433.     }
  434.     arg = &buf[strlen (*cmdp)];
  435.     while (*arg == ' ')
  436.         arg++;
  437.  
  438.     /* Execute specific command */
  439.     switch (cmdp - commands) {
  440.         case USER_CMD:
  441.             free (ftp.username);
  442.             ftp.username = strdup (arg);
  443. #if 0
  444.             if(sp_user(ftp.username)) {
  445.                 time(&ftp.ttim);
  446.                 usprintf(ftp.control,challenge,ftp.ttim);
  447.             } else
  448. #endif
  449.             if (isanonymous (arg))
  450.                 usprintf (ftp.control, anonokay);
  451.             else
  452.                 usprintf (ftp.control, givepass);
  453.             break;
  454.         case TYPE_CMD:
  455.             switch (arg[0]) {
  456.                 case 'A':
  457.                 case 'a':    /* Ascii */
  458.                     ftp.type = ASCII_TYPE;
  459.                     usprintf (ftp.control, typeok, arg);
  460.                     break;
  461.                 case 'l':
  462.                 case 'L':
  463.                     while (*arg != ' ' && *arg != '\0')
  464.                         arg++;
  465.                     if (*arg == '\0' || *++arg != '8') {
  466.                         usprintf (ftp.control, only8);
  467.                         break;
  468.                     }
  469.                     ftp.type = LOGICAL_TYPE;
  470.                     ftp.logbsize = 8;
  471.                     usprintf (ftp.control, typeok, arg);
  472.                     break;
  473.                 case 'B':
  474.                 case 'b':    /* Binary */
  475.                 case 'I':
  476.                 case 'i':    /* Image */
  477.                     ftp.type = IMAGE_TYPE;
  478.                     usprintf (ftp.control, typeok, arg);
  479.                     break;
  480.                 default:    /* Invalid */
  481.                     usprintf (ftp.control, badtype, arg);
  482.                     break;
  483.             }
  484.             break;
  485.         case QUIT_CMD:
  486.             usprintf (ftp.control, bye);
  487.             goto finish;
  488.         case RNFR_CMD:
  489.             file = addroot (ftp.curdirs->dir, arg);
  490.             if (!permcheck (ftp.path, ftp.perms, RNFR_CMD, file))
  491.                 usprintf (ftp.control, noperm);
  492.             else if (access (file, 6))
  493.                 usprintf (ftp.control, cantopen, file, SYS_ERRLIST(errno));
  494.             else {
  495.                 usprintf (ftp.control, pendingto);
  496.                 rnfrom = strdup (file);
  497.             }
  498.             free (file);
  499.             break;
  500.         case RNTO_CMD:
  501.             file = addroot (ftp.curdirs->dir, arg);
  502.             if (rnfrom == NULLCHAR)
  503.                 usprintf (ftp.control, badseq);
  504.             else {
  505.                 if (!permcheck (ftp.path, ftp.perms, RNTO_CMD, file))
  506.                     usprintf (ftp.control, noperm);
  507.                 else {
  508.                     if (rename (rnfrom, file) == -1)
  509.                         usprintf (ftp.control, norename, SYS_ERRLIST(errno));
  510.                     else
  511.                         usprintf (ftp.control, okay);
  512.                 }
  513.                 free (rnfrom);
  514.                 rnfrom = NULLCHAR;
  515.             }
  516.             free (file);
  517.             break;
  518.         case RETR_CMD:
  519.         case RSME_CMD:
  520.             file = addroot (ftp.curdirs->dir, arg);
  521.             switch (ftp.type) {
  522.                 case IMAGE_TYPE:
  523.                 case LOGICAL_TYPE:
  524.                     mode = READ_BINARY;
  525.                     break;
  526.                 default:
  527.                 case ASCII_TYPE:
  528.                     mode = READ_TEXT;
  529.                     break;
  530.             }
  531.             if (!permcheck (ftp.path, ftp.perms, RETR_CMD, file))
  532.                 usprintf (ftp.control, noperm);
  533. #ifdef UNIX
  534.             else if (!ftpsecuritycheck (file, ftp.perms, R_OK) || (ftp.fp = fopen (file, mode)) == NULLFILE)
  535. #else
  536.             else if ((ftp.fp = fopen (file, mode)) == NULLFILE)
  537. #endif
  538.                 usprintf (ftp.control, cantopen, file, SYS_ERRLIST(errno));
  539.             else {
  540.                 if ((cmdp - commands) == RSME_CMD) {
  541.                     log (ftp.control, "RSME %s", file);
  542.                     if (ftp.type == ASCII_TYPE && isbinary (ftp.fp))
  543.                         usprintf (ftp.control, binwarn, file);
  544.  
  545.                     (void) sendit (&ftp, "RSME", file);
  546.                 } else {
  547.                     log (ftp.control, "RETR %s", file);
  548.                     if (ftp.type == ASCII_TYPE && isbinary (ftp.fp))
  549.                         usprintf (ftp.control, binwarn, file);
  550.  
  551.                     (void) sendit (&ftp, "RETR", file);
  552.                 }
  553.             }
  554.             free (file);
  555.             break;
  556.         case SIZE_CMD:
  557.             file = addroot (ftp.curdirs->dir, arg);
  558.             if (!permcheck (ftp.path, ftp.perms, RETR_CMD, file))
  559.                 usputs (ftp.control, noperm);
  560.             else if ((ftp.fp = fopen (file, READ_BINARY)) != NULLFILE) {
  561.                 usprintf (ftp.control, filesize, filelength (fileno (ftp.fp)));
  562.                 (void) fclose (ftp.fp);
  563.             } else if (!access (file, 0))
  564.                 usprintf (ftp.control, notaplain, file);
  565.             else
  566.                 usprintf (ftp.control, nosuchfile, file);
  567.  
  568.             free (file);
  569.             break;
  570.         case STOR_CMD:
  571.             cp = "STOR";
  572.             goto store2;
  573.         case APPE_CMD:
  574.             cp = "APPE";
  575.             goto store2;
  576.         case RPUT_CMD:
  577.             cp = "RPUT";
  578. store2:
  579.             file = addroot (ftp.curdirs->dir, arg);
  580.             switch (ftp.type) {
  581.                 case IMAGE_TYPE:
  582.                 case LOGICAL_TYPE:
  583.                     if (cmdp - commands != STOR_CMD)
  584.                         mode = APPEND_BINARY;
  585.                     else
  586.                         mode = WRITE_BINARY;
  587.                     break;
  588.                 default:
  589.                 case ASCII_TYPE:
  590.                     if (cmdp - commands != STOR_CMD)
  591.                         mode = APPEND_TEXT;
  592.                     else
  593.                         mode = WRITE_TEXT;
  594.                     break;
  595.             }
  596.             if (!permcheck (ftp.path, ftp.perms, cmdp - commands, file))
  597.                 usprintf (ftp.control, noperm);
  598. #ifdef UNIX
  599.             else if (!ftpsecuritycheck (file, ftp.perms, W_OK) || (ftp.fp = fopen (file, mode)) == NULLFILE)
  600. #else
  601.             else if ((ftp.fp = fopen (file, mode)) == NULLFILE)
  602. #endif
  603.                 usprintf (ftp.control, cantmake, file, SYS_ERRLIST(errno));
  604.             else {
  605.                 log (ftp.control, "%s %s", cp, file);
  606.                 (void) recvit (&ftp, cp, file);
  607. #ifdef UNIX
  608.                 if (CREATEsecure) {
  609.                     (void) chown (file, (uid_t) CREATEuid, (gid_t) CREATEgid);
  610.                     (void) chmod (file, (mode_t) CREATEmask);
  611.                 }
  612. #endif
  613.             }
  614.             free (file);
  615.             break;
  616.         case PORT_CMD:
  617.             if (pport (&ftp.port, arg) == -1)
  618.                 usprintf (ftp.control, badport);
  619.             else
  620.                 usprintf (ftp.control, portok);
  621.  
  622.             break;
  623. #ifndef CPM
  624.         case LIST_CMD:
  625.         case NLST_CMD:
  626.             file = addroot (ftp.curdirs->dir, defpath (ftp.curdirs, arg));
  627.             if (!permcheck (ftp.path, ftp.perms, RETR_CMD, file))
  628.                 usprintf (ftp.control, noperm);
  629.             else {
  630. #ifdef UNIX
  631.                 if (ftpsecuritycheck (file, ftp.perms, R_OK))    {
  632.  
  633. #endif
  634.                     cp = Command->curdirs->dir;
  635.                     Command->curdirs->dir = ftp.curdirs->dir;
  636.                     if ((ftp.fp = dir (file, ((cmdp - commands) == LIST_CMD) ? 2 : 0)) == NULLFILE)
  637.                         usprintf (ftp.control, nodir, file, SYS_ERRLIST(errno));
  638.                     else
  639.                         (void) sendit (&ftp, ((cmdp - commands) == LIST_CMD) ? "LIST" : "NLST", file);
  640.                     Command->curdirs->dir = cp;
  641. #ifdef UNIX
  642.                 } else
  643.                     usprintf (ftp.control, noperm);
  644. #endif
  645.             }
  646.             free (file);
  647.             break;
  648.         case CDUP_CMD:
  649.             sprintf (arg, "..");    /* and fall through */
  650.         case CWD_CMD:
  651. #ifdef old_CALLSERVER
  652.             /* if the requested path contains the CROM drive letter:  */
  653.             if (CDROM != NULLCHAR && strnicmp (CDROM, arg, 2) == 0) {
  654.                 if (strchr (arg, '/') == NULLCHAR) {
  655.                     file = (char *) mallocw (strlen (arg) + 2);
  656.                     sprintf (file, "%s/", arg);
  657.                 } else
  658.                     file = strdup (arg);
  659.                 if (!permcheck (ftp.path, ftp.perms, RETR_CMD, file)) {
  660.                     usprintf (ftp.control, noperm);
  661.                     free (file);
  662. #ifdef MSDOS
  663.                     /* Don'tcha just LOVE %%$#@!! MS-DOS? - which is what we are running */
  664.                 } else if (file[2] == '/' || access (file, 0) == 0) {
  665. #else
  666.                 } else if (access (file, 0) == 0) {    /* See if it exists */
  667. #endif
  668.                     /* Succeeded, record in control block */
  669.                     free (ftp.cd);
  670.                     ftp.cd = file;
  671.                     usprintf (ftp.control, "You may return to your default drive & directory by entering:\n\t\t\"cd %s\"\n\n", ftp.path);
  672.                     usprintf (ftp.control, pwdmsg, file);
  673.                 } else {
  674.                     /* Failed, don't change anything */
  675.                     usprintf (ftp.control, nodir, file, SYS_ERRLIST(errno));
  676.                     free (file);
  677.                 }
  678.                 break;
  679.             }
  680.             /* requested path does not contain CDROM drive letter:                      */
  681.             /* if current dir is in CDROM - and a "off-root" is requested:
  682.                go back to default path.        */
  683.             if ((CDROM != NULLCHAR && strnicmp (ftp.cd, CDROM, 2) == 0) && (arg[0] == '/')) {
  684.                 free (ftp.cd);
  685.                 ftp.cd = strdup (ftp.path);    /* go back to default path            */
  686.             }
  687. #endif /* #ifdef CALLSERVER  */
  688.             if (*arg == '/' || *arg == '\\')
  689.                 file = addroot (ftp.path, &arg[1]);
  690.             else
  691.                 file = addroot (ftp.curdirs->dir, arg);
  692.             if (!permcheck (ftp.path, ftp.perms, RETR_CMD, file))
  693.                 usprintf (ftp.control, noperm);
  694.             else if (dir_ok (file, ftp.curdirs)) {
  695.                 /* Succeeded */
  696.                 /* If exists, send the contents of 'desc.ftp' in the new
  697.                  * directory...
  698.                  */
  699.                 strncpy (buf, file, 512);
  700.                 if ((fpm = fopen (strcat (buf, "/desc.ftp"), "r")) != NULL) {
  701.                     sendmsgfile (ftp.control, 257, buf, sizeof (buf), fpm);
  702.                     (void) fclose (fpm);
  703.                 }
  704. #ifndef MSDOS
  705.                 /* If exists, send the contents of '.message' in the new
  706.                  * directory...
  707.                  */
  708.                 strncpy (buf, file, 512);
  709.                 if ((fpm = fopen (strcat (buf, "/.message"), "r")) != NULL) {
  710.                     sendmsgfile (ftp.control, 257, buf, sizeof (buf), fpm);
  711.                     (void) fclose (fpm);
  712.                 }
  713. #endif
  714.  
  715.                 usprintf (ftp.control, pwdmsg,
  716.                     (!strcmp (ftp.root, ftp.curdirs->dir)) ? "/"
  717.                     : (!strncmp (ftp.root, ftp.curdirs->dir, strlen (ftp.root)))
  718.                     ? &ftp.curdirs->dir[strlen (ftp.root)]
  719.                     : ftp.curdirs->dir);
  720.             } else
  721.                 /* Failed, nothing changed */
  722.                 usprintf (ftp.control, nodir, arg, SYS_ERRLIST(errno));
  723.             free (file);
  724.             break;
  725.         case XPWD_CMD:
  726.         case PWD_CMD:
  727.             usprintf (ftp.control, pwdmsg,
  728.                 (!strcmp (ftp.root, ftp.curdirs->dir)) ? "/"
  729.                 : (!strncmp (ftp.root, ftp.curdirs->dir, strlen (ftp.root)))
  730.                 ? &ftp.curdirs->dir[strlen (ftp.root)]
  731.                 : ftp.curdirs->dir);
  732.             break;
  733. #else
  734.         case LIST_CMD:
  735.         case NLST_CMD:
  736.         case CWD_CMD:
  737.         case XPWD_CMD:
  738.         case PWD_CMD:
  739. #endif
  740.         case ACCT_CMD:
  741.             usprintf (ftp.control, unimp);
  742.             break;
  743.         case HELP_CMD:
  744.             usputs (ftp.control, help);
  745.             for (cmdp = commands, i = buf[0] = 0; *cmdp != NULLCHAR; cmdp++) {
  746.                 strcat (buf, "   ");
  747.                 strcat (buf, *cmdp);
  748.                 if (strlen (*cmdp) == 3)
  749.                     strcat (buf, " ");
  750.                 if (i++ == 9) {
  751.                     (void) strupr (buf);
  752.                     usprintf (ftp.control, "%s\n", buf);
  753.                     i = buf[0] = 0;
  754.                 }
  755.             }
  756.             if (i) {
  757.                 (void) strupr (buf);
  758.                 usprintf (ftp.control, "%s\n", buf);
  759.             }
  760.             usprintf (ftp.control, "214 Report problems to sysop@%s\n", Hostname);
  761.             break;
  762.         case NOOP_CMD:
  763.             usputs (ftp.control, okay);
  764.             break;
  765.         case DELE_CMD:
  766.             file = addroot (ftp.curdirs->dir, arg);
  767.             if (!permcheck (ftp.path, ftp.perms, DELE_CMD, file))
  768.                 usprintf (ftp.control, noperm);
  769.             else if (unlink (file) == 0) {
  770.                 log (ftp.control, "DELE %s", file);
  771.                 usprintf (ftp.control, deleok);
  772.             } else
  773.                 usprintf (ftp.control, delefail, SYS_ERRLIST(errno));
  774.  
  775.             free (file);
  776.             break;
  777.         case PASS_CMD:
  778.             if (ftp.username == NULLCHAR)
  779.                 usprintf (ftp.control, userfirst);
  780.             else
  781.                 ftplogin (&ftp, arg);
  782.             break;
  783. #ifndef    CPM
  784.         case XMKD_CMD:
  785.         case MKD_CMD:
  786.             file = addroot (ftp.curdirs->dir, arg);
  787.             if (!permcheck (ftp.path, ftp.perms, MKD_CMD, file))
  788.                 usprintf (ftp.control, noperm);
  789.             else if (mkdir (file, (mode_t) 0777) == 0) {
  790.                 log (ftp.control, "MKD %s", file);
  791.                 usprintf (ftp.control, mkdok);
  792.             } else
  793.                 usprintf (ftp.control, cantmake, file, SYS_ERRLIST(errno));
  794.  
  795.             free (file);
  796.             break;
  797.         case XRMD_CMD:
  798.         case RMD_CMD:
  799.             file = addroot (ftp.curdirs->dir, arg);
  800.             if (!permcheck (ftp.path, ftp.perms, RMD_CMD, file))
  801.                 usprintf (ftp.control, noperm);
  802.             else if (rmdir (file) == 0) {
  803.                 log (ftp.control, "RMD %s", file);
  804.                 usprintf (ftp.control, deleok);
  805.             } else
  806.                 usprintf (ftp.control, delefail, SYS_ERRLIST(errno));
  807.  
  808.             free (file);
  809.             break;
  810.         case STRU_CMD:
  811.             if (tolower (arg[0]) != 'f')
  812.                 usprintf (ftp.control, unsupp);
  813.             else
  814.                 usprintf (ftp.control, okay);
  815.             break;
  816.         case MODE_CMD:
  817.             if (tolower (arg[0]) != 's')
  818.                 usprintf (ftp.control, unsupp);
  819.             else
  820.                 usprintf (ftp.control, okay);
  821.             break;
  822.         case SYST_CMD:
  823.             usprintf (ftp.control, syst, System, NBBY, Version);
  824.             break;
  825.         case PASV_CMD:        /*PASV mod*/
  826.             /* Send the PASV message. Use the IP address
  827.              * on the local end of our control connection. */
  828.             if (ftp.data != -1)    /* left over error - kill the socket first */
  829.                 close_s (ftp.data);
  830.  
  831.             ftp.data = socket (AF_INET, SOCK_STREAM, 0);
  832.             (void) listen (ftp.data, 0);
  833.             i = SOCKSIZE;
  834.             (void) getsockname (ftp.data, (char *) &lsocket, &i);
  835.             if (!i)
  836.                 break;
  837.             i = SOCKSIZE;
  838.             (void) getsockname (ftp.control, (char *) &lcsocket, &i);
  839.             if (!i)
  840.                 break;
  841.             lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
  842.             /* send the address to the client.  */
  843.             SendPasv (ftp.control, &lsocket);
  844.             break;
  845.         case XMD5_CMD:        /*PASV mod*/
  846.             file = addroot (ftp.curdirs->dir, arg);
  847.             switch (ftp.type) {
  848.                 case IMAGE_TYPE:
  849.                 case LOGICAL_TYPE:
  850.                     mode = READ_BINARY;
  851.                     break;
  852.                 default:
  853.                 case ASCII_TYPE:
  854.                     mode = READ_TEXT;
  855.                     break;
  856.             }
  857.             if (!permcheck (ftp.path, ftp.perms, RETR_CMD, file))
  858.                 usprintf (ftp.control, noperm);
  859. #ifdef UNIX
  860.             else if (!ftpsecuritycheck (file, ftp.perms, R_OK) || (ftp.fp = fopen (file, mode)) == NULLFILE)
  861. #else
  862.             else if ((ftp.fp = fopen (file, mode)) == NULLFILE)
  863. #endif
  864.                 usprintf (ftp.control, cantopen, file, SYS_ERRLIST(errno));
  865.             else {
  866.                 char hash[16];
  867.  
  868.                 log (ftp.control, "XMD5 %s", file);
  869.                 if (ftp.type == ASCII_TYPE && isbinary (ftp.fp))
  870.                     usprintf (ftp.control, binwarn, file);
  871.  
  872.                 (void) md5hash (ftp.fp, hash, ftp.type == ASCII_TYPE);
  873.                 (void) fclose (ftp.fp);
  874.                 ftp.fp = NULLFILE;
  875.                 usprintf (ftp.control, "200 ");
  876.                 for (i = 0; i < 16; i++)
  877.                     usprintf (ftp.control, "%02x", hash[i] & 0xff);
  878.                 usprintf (ftp.control, " %s\n", file);
  879.             }
  880.             free (file);
  881.             break;
  882. #ifdef LZW
  883.         case XLZW_CMD:
  884.             if (ftp.lzw)
  885.                 usprintf (ftp.control, "550 Already using LZW compression\n");
  886.             else {
  887.                 usprintf (ftp.control, okay);
  888.                 sscanf (&buf[5], "%d %d", &ftp.lzwbits, &ftp.lzwmode);
  889.                 ftp.lzw = 1;
  890.             }
  891.             break;
  892.         default:
  893.             break;
  894. #endif
  895.     }
  896. #endif
  897.     goto loop;
  898.  
  899. finish:
  900.  
  901. #ifdef FTPTDISC
  902.     stop_timer (&ftp.tdisc);
  903. #endif
  904.  
  905.     log (ftp.control, "close FTP from '%s'", ftp.username);
  906.     FtpUsers--;
  907. #ifdef XSERVER
  908.     xnotify (X_FTP);
  909. #endif
  910.     /* Clean up */
  911.     close_s (ftp.control);
  912.     if (ftp.data != -1)
  913.         close_s (ftp.data);
  914.     if (ftp.fp != NULLFILE)
  915.         (void) fclose (ftp.fp);
  916.     free (ftp.username);
  917.     free (ftp.path);
  918.     free_dirs (&dirs);
  919.     free (rnfrom);
  920. }
  921.  
  922.  
  923.  
  924. /* Shut down FTP server */
  925. int
  926. ftp0 (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  927. {
  928.     return (deleteserver (&Sftp));
  929. }
  930.  
  931.  
  932.  
  933. static
  934. int
  935. pport (struct sockaddr_in *sock, char *arg)
  936. {
  937. uint32 n;
  938. int i;
  939.  
  940.     n = 0;
  941.     for (i = 0; i < 4; i++) {
  942.         n = (uint32) atoi (arg) + (n << 8);
  943.         if ((arg = strchr (arg, ',')) == NULLCHAR)
  944.             return -1;
  945.         arg++;
  946.     }
  947.     sock->sin_addr.s_addr = n;
  948.     n = (uint32) atoi (arg);
  949.     if ((arg = strchr (arg, ',')) == NULLCHAR)
  950.         return -1;
  951.     arg++;
  952.     n = (uint32) atoi (arg) + (n << 8);
  953.     sock->sin_port = (int16) n;
  954.     return 0;
  955. }
  956.  
  957.  
  958.  
  959. /* Attempt to log in the user whose name is in ftp->username and password
  960.  * in pass
  961.  */
  962. static void
  963. ftplogin (struct ftpserv *ftp, char *pass)
  964. {
  965. char *path, buf[128], *cp;
  966. char *p, *cp1;
  967. time_t t;
  968. FILE *fp;
  969. int anony = 0;
  970.  
  971.     path = mallocw (200);
  972.     if ((ftp->perms = userlogin (ftp->username, pass, &path, 200, &anony)) == -1) {
  973.         log (ftp->control, "FTP login refused - '%s'", ftp->username);
  974.         usprintf (ftp->control, noperm);
  975.         free (path);
  976.         return;
  977.     }
  978.     /* Set up current directory and path prefix */
  979.     ftp->path = strdup (path);
  980.     cp = strdup (path);
  981.     if ((cp1 = strchr (cp, ';')) != NULLCHAR)
  982.         *cp1 = '\0';
  983.     if ((cp1 = strchr (cp, '=')) != NULLCHAR)
  984.         *cp1 = '\0';
  985. #ifdef MSDOS
  986.     if (*cp == '/' || *cp == '\\')    {
  987.         sprintf (buf, "%c:%s", ftp->curdirs->drv + '`', cp);
  988.         ftp->root = strdup (buf);
  989.     } else
  990. #endif
  991.         ftp->root = strdup (cp);    /*lint !e539 */
  992.     free (cp);
  993.  
  994.     {
  995.     FILE *out;
  996.  
  997.         sprintf (buf, "%s/ftp.log", LOGdir);
  998.         if ((out = fopen (buf, APPEND_TEXT)) != NULLFILE) {
  999.             time_t tt;
  1000.  
  1001.             (void) time (&tt);
  1002.             fprintf (out, "FTP from %s (%s) on %s", ftp->username, pass, ptime (&tt));
  1003.             (void) fclose (out);
  1004.         }
  1005.     }
  1006.  
  1007.     (void) time (&t);
  1008.     cp = ctime (&t);
  1009.     usprintf (ftp->control, banner1, cp);
  1010.     usprintf (ftp->control, banner2, Hostname, FtpUsers, FtpMaxUsers);
  1011.  
  1012.     /* everyone gets the ftpmotd file, if it exists */
  1013.     if ((fp = fopen (Ftpmotd, "r")) != NULL) {
  1014.         sendmsgfile (ftp->control, 230, buf, sizeof (buf), fp);
  1015.         (void) fclose (fp);
  1016.     }
  1017.     /* if there is a message.ftp file in the login dir, send it too */
  1018.     sprintf (buf, "%s%s%s", path, (path[strlen (path) - 1] == '/') ? "" : "/", "message.ftp");
  1019.     if ((fp = fopen (buf, "r")) != NULL) {
  1020.         sendmsgfile (ftp->control, 230, buf, sizeof (buf), fp);
  1021.         (void) fclose (fp);
  1022.     }
  1023.     path = strdup (ftp->path);
  1024.     if ((p = strpbrk (path, "=;")) != NULLCHAR)
  1025.         *p = 0;
  1026.     if (dir_ok (path, ftp->curdirs)) {
  1027.         /* Succeeded */
  1028.         /* If exists, send the contents of 'desc.ftp' in the new directory... */
  1029.         sprintf (buf, "%s/desc.ftp", path);
  1030.         if ((fp = fopen (buf, "r")) != NULL) {
  1031.             sendmsgfile (ftp->control, 230, buf, sizeof (buf), fp);
  1032.             (void) fclose (fp);
  1033.         }
  1034.     }
  1035.     free (path);
  1036.     if (!anony) {
  1037.         usprintf (ftp->control, logged);
  1038.         log (ftp->control, "FTP login - '%s'", ftp->username);
  1039.     } else {
  1040.         usprintf (ftp->control, loggeda);
  1041.         log (ftp->control, "FTP anonymous login - '%s' (%s)", ftp->username, pass);
  1042.     }
  1043.     usflush (ftp->control);
  1044.     kwait (NULL);
  1045. }
  1046.  
  1047.  
  1048.  
  1049. #ifdef    MSDOS
  1050. /* Illegal characters in a DOS filename */
  1051. static char badchars[] = "\"[]|<>+=;,";
  1052. #endif
  1053.  
  1054.  
  1055.  
  1056. /* Return 1 if the file operation is allowed, 0 otherwise */
  1057. int
  1058. permcheck (char *path, long perms, int op, char *file)
  1059. {
  1060. char *cp, *cp1;
  1061. int newperms;
  1062. int match = FALSE;
  1063. int notabove = FALSE;
  1064.  
  1065.     if (file == NULLCHAR || path == NULLCHAR)
  1066.         return 0;    /* Probably hasn't logged in yet */
  1067.  
  1068.     /* To get to the CDROM - EVERYBODY gets read privs, regardless of what
  1069.        /ftpusers has to say about it!!! - kb7yw */
  1070.  
  1071. #ifdef CALLSERVER
  1072.     if (CDROM != NULLCHAR && strnicmp (file, CDROM, 2) == 0) {
  1073.         /* Check for characters illegal in MS-DOS file names */
  1074.         for (cp = badchars; *cp != '\0'; cp++) {
  1075.             if (strchr (&file[2], *cp) != NULLCHAR)
  1076.                 return 0;
  1077.         }
  1078.  
  1079.         switch (op) {    /* What to do when the user is on the cd-rom drive      */
  1080.             case RETR_CMD:    /* Everybody gets read privs regardless of ftpusers  */
  1081.                 /* User has permission to read files */
  1082.                 return 1;
  1083.             case DELE_CMD:
  1084.             case RMD_CMD:
  1085.                 /* User must not have permission to (over)write files */
  1086.             case STOR_CMD:
  1087.             case MKD_CMD:
  1088.                 /* User must NOT have permission to (over)write files */
  1089.                 return 0;
  1090.         }        /* switch(op) */
  1091.     }            /* if strncmp(....  */
  1092. # endif                /* #ifdef CALLSERVER  */
  1093. #ifndef MAC
  1094.     /* The target file must be under the user's allowed search path */
  1095.     /* We let them specify multiple paths using path;path... -russ */
  1096.     /* Allow /nos/public;/nos/public/incoming=3 style path statements -bruce */
  1097.     for (cp = path; *cp != '\0'; cp = cp1 + 1) {
  1098.         char *cp2;
  1099.  
  1100.         newperms = perms;
  1101.         if ((cp1 = strchr (cp, ';')) == NULLCHAR)
  1102.             cp1 = &cp[strlen(cp) - 1];
  1103.         cp2 = strchr (cp, '=');
  1104.         if (!cp2 || (cp2 > cp1))
  1105.             cp2 = cp1;
  1106.         else
  1107.             newperms = atoi (cp2 + 1);
  1108.         /* Take care of the case when we have a path statement in ftpusers
  1109.            like:  /nos/public;/nos/public/incoming=3 and the user cwd's to
  1110.                /nos.  Make sure the user is not above the smallest length path
  1111.            so that we can have path statements like: /nos/public;/nos=1;/nos...
  1112.         */
  1113.         if ((int) strlen (file) >= (cp2 - cp))
  1114.             notabove = TRUE;
  1115.         if (!strnicmp (file, cp, (unsigned) (cp2 - cp))
  1116. #ifdef MSDOS
  1117.             || !strnicmp (file + 2, cp, cp2 - cp)
  1118. #endif
  1119.             ) {
  1120.             match = TRUE;
  1121.             perms = newperms;
  1122.         }
  1123.     }
  1124.     /* We must have both a match and not be above the smallest level to
  1125.        continue */
  1126.     if (!match || !notabove)
  1127.         return 0;
  1128. #endif
  1129.  
  1130. #ifdef    MSDOS
  1131.     /* Check for characters illegal in MS-DOS file names */
  1132.     for (cp = badchars; *cp != '\0'; cp++) {
  1133.         if (strchr (file, *cp) != NULLCHAR)
  1134.             return 0;
  1135.     }
  1136. #endif
  1137.  
  1138.     switch (op) {
  1139.         case RETR_CMD:
  1140.             /* User must have permission to read files */
  1141.             if (perms & FTP_READ)
  1142.                 return 1;
  1143.             return 0;
  1144.         case DELE_CMD:
  1145.         case RMD_CMD:
  1146.         case RPUT_CMD:
  1147.         case APPE_CMD:
  1148.             /* User must have permission to (over)write files */
  1149.             if (perms & FTP_WRITE)
  1150.                 return 1;
  1151.             return 0;
  1152.         case RNFR_CMD:
  1153.         case RNTO_CMD:
  1154.         case STOR_CMD:
  1155.         case MKD_CMD:
  1156.             /* User must have permission to (over)write files, or permission
  1157.              * to create them if the file doesn't already exist
  1158.              */
  1159.             if (perms & FTP_WRITE)
  1160.                 return 1;
  1161.             if (access (file, 2) == -1 && (perms & FTP_CREATE))
  1162.                 return 1;
  1163.             return 0;
  1164.         default:
  1165.             break;
  1166.     }
  1167.     return 0;        /* "can't happen" -- keep lint happy */
  1168. }
  1169.  
  1170.  
  1171.  
  1172. static int
  1173. sendit (struct ftpserv *ftp, const char *command, char *file)
  1174. {
  1175. long total, starting;
  1176. unsigned long check;
  1177. struct sockaddr_in dport;
  1178. char *cp, *cp2;
  1179. char fsizetext[20];    /* N1BEE */
  1180. int pasv = 0;
  1181.  
  1182.     if (ftp->data != -1)
  1183.         pasv = 1;
  1184.  
  1185.     fsizetext[0] = 0;
  1186.     if (!pasv) {
  1187.         ftp->data = socket (AF_INET, SOCK_STREAM, 0);
  1188.         dport.sin_family = AF_INET;
  1189.         dport.sin_addr.s_addr = INADDR_ANY;
  1190.         dport.sin_port = IPPORT_FTPD;
  1191.         (void) bind (ftp->data, (char *) &dport, SOCKSIZE);
  1192.     }
  1193.     sprintf (fsizetext, "(%lu bytes)", filelength (fileno (ftp->fp)));
  1194.     usprintf (ftp->control, sending, command, (strlen (file) == strlen (ftp->path)) ? "/" : &file[strlen (ftp->path)], fsizetext);    /* N1BEE */
  1195.     if (!pasv) {
  1196.         if (connect (ftp->data, (char *) &ftp->port, SOCKSIZE) == -1) {
  1197.             (void) fclose (ftp->fp);
  1198.             ftp->fp = NULLFILE;
  1199.             close_s (ftp->data);
  1200.             ftp->data = -1;
  1201.             usprintf (ftp->control, noconn);
  1202.             return -1;
  1203.         }
  1204.     } else {        /* PASV mode */
  1205.         /* wait for the client to open the connection */
  1206.         /* ftp->data has been setup already */
  1207.         (void) accept (ftp->data, NULLCHAR, (int *) NULL);
  1208.     }
  1209.     if (strcmp (command, "RSME") == 0) {
  1210.         total = -1;
  1211.         cp = mallocw (40);
  1212.         if (recvline (ftp->control, (unsigned char *) cp, 40) == -1) {
  1213.             free (cp);
  1214.             goto send_err;
  1215.         }
  1216.         starting = atol (cp);
  1217.         /* If checksum field is not present go on anyway, for compatibility
  1218.          * with previous scheme. If present check it and barf if wrong.
  1219.          */
  1220.         cp2 = strchr (cp, ' ');
  1221.         if (cp2 != NULLCHAR) {
  1222.             check = (unsigned long) atol (cp2);
  1223.             check -= checksum (ftp->fp, starting);
  1224.             if (check != 0) {
  1225.                 free (cp);
  1226.                 usprintf (ftp->control, badcheck);
  1227.                 (void) shutdown (ftp->data, 1);    /* Blow away data connection */
  1228.                 goto send_err;
  1229.             }
  1230.         } else if (fseek (ftp->fp, starting, SEEK_SET) != 0) {
  1231.             free (cp);
  1232.             usprintf (ftp->control, noconn);
  1233.             (void) shutdown (ftp->data, 2);    /* Blow away data connection */
  1234.             goto send_err;
  1235.         }
  1236.     }
  1237. #ifdef FTPTDISC
  1238.     /* Turn off the timeout timer here, some ftp's could
  1239.      * take a long time with sloooow packet channels - WG7J
  1240.      */
  1241.     stop_timer (&ftp->tdisc);
  1242. #endif
  1243.  
  1244. #ifdef LZW
  1245.     if (ftp->lzw)
  1246.         lzwinit (ftp->data, ftp->lzwbits, ftp->lzwmode);
  1247. #endif
  1248.  
  1249.     /* Do the actual transfer */
  1250.     total = sendfile (ftp->fp, ftp->data, ftp->type, 0);
  1251.  
  1252. #ifdef FTPTDISC
  1253.     /* And turn it back on now */
  1254.     start_timer (&ftp->tdisc);
  1255. #endif
  1256.  
  1257.     if (total == -1) {
  1258.         /* An error occurred on the data connection */
  1259.         usprintf (ftp->control, noconn);
  1260.         (void) shutdown (ftp->data, 2);    /* Blow away data connection */
  1261.     } else
  1262.         usprintf (ftp->control, txok);
  1263.  
  1264. send_err:
  1265.     (void) fclose (ftp->fp);
  1266.     ftp->fp = NULLFILE;
  1267.     close_s (ftp->data);
  1268.     ftp->data = -1;
  1269. #ifdef LZW
  1270.     ftp->lzw = 0;
  1271. #endif
  1272.     if (total == -1)
  1273.         return -1;
  1274.     else
  1275.         return 0;
  1276. }
  1277.  
  1278.  
  1279.  
  1280. static int
  1281. recvit (struct ftpserv *ftp, const char *command, char *file)
  1282. {
  1283. struct sockaddr_in dport;
  1284. long total, starting;
  1285. int pasv = 0;
  1286.  
  1287.     if (ftp->data != -1)
  1288.         pasv = 1;
  1289.  
  1290.     if (!pasv) {
  1291.         ftp->data = socket (AF_INET, SOCK_STREAM, 0);
  1292.         dport.sin_family = AF_INET;
  1293.         dport.sin_addr.s_addr = INADDR_ANY;
  1294.         dport.sin_port = IPPORT_FTPD;
  1295.         (void) bind (ftp->data, (char *) &dport, SOCKSIZE);
  1296.     }
  1297.     usprintf (ftp->control, sending, command, file, "");
  1298.  
  1299.     if (!pasv) {
  1300.         if (connect (ftp->data, (char *) &ftp->port, SOCKSIZE) == -1) {
  1301.             (void) fclose (ftp->fp);
  1302.             ftp->fp = NULLFILE;
  1303.             close_s (ftp->data);
  1304.             ftp->data = -1;
  1305.             usprintf (ftp->control, noconn);
  1306.             return -1;
  1307.         }
  1308.     } else {        /* PASV mode */
  1309.         /* wait for the client to open the connection */
  1310.         /* ftp->data has been setup already */
  1311.         (void) accept (ftp->data, NULLCHAR, (int *) NULL);
  1312.     }
  1313.     if (strcmp (command, "APPE") == 0)
  1314.         fseek (ftp->fp, 0, SEEK_END);
  1315.     if (strcmp (command, "RPUT") == 0) {
  1316.         if ((starting = (long) getsize (ftp->fp)) == -1)
  1317.             starting = 0L;
  1318.         usprintf (ftp->control, "%lu %lu\n", starting, checksum (ftp->fp, starting));
  1319.         fseek (ftp->fp, starting, SEEK_SET);
  1320.     }
  1321. #ifdef FTPTDISC
  1322.     /* Turn of the timeout timer here; some ftp's could
  1323.      * take a long time with sloooow packet channels - WG7J
  1324.      */
  1325.     stop_timer (&ftp->tdisc);
  1326. #endif
  1327.  
  1328. #ifdef LZW
  1329.     if (ftp->lzw)
  1330.         lzwinit (ftp->data, ftp->lzwbits, ftp->lzwmode);
  1331. #endif
  1332.  
  1333.     /* Do the actual transfer */
  1334.     total = recvfile (ftp->fp, ftp->data, ftp->type, 0);
  1335.  
  1336. #ifdef FTPTDISC
  1337.     /* And turn it back on now */
  1338.     start_timer (&ftp->tdisc);
  1339. #endif
  1340.  
  1341. #ifdef    CPM
  1342.     if (ftp->type == ASCII_TYPE)
  1343.         putc (CTLZ, ftp->fp);
  1344. #endif
  1345.     if (total == -1) {
  1346.         /* An error occurred while writing the file */
  1347.         usprintf (ftp->control, writerr, SYS_ERRLIST(errno));
  1348.         (void) shutdown (ftp->data, 2);    /* Blow it away */
  1349.     } else
  1350.         usprintf (ftp->control, rxok);
  1351.     close_s (ftp->data);
  1352.     ftp->data = -1;
  1353.     (void) fclose (ftp->fp);
  1354.     ftp->fp = NULLFILE;
  1355. #ifdef LZW
  1356.     ftp->lzw = 0;
  1357. #endif
  1358.     if (total == -1)
  1359.         return -1;
  1360.     else
  1361.         return 0;
  1362. }
  1363.  
  1364.  
  1365.  
  1366. #ifdef UNIX
  1367. #if 0
  1368. extern uid_t geteuid (void);
  1369. extern gid_t getegid (void);
  1370. #endif
  1371.  
  1372. int
  1373. ftpsecuritycheck (char *filename, int perms, int mode)
  1374. {
  1375. int accval;        /*lint -esym(550, accval) */
  1376. int retval;
  1377. int fd;
  1378. char *buf, *cp;
  1379. uid_t ruid = getuid ();
  1380. gid_t rgid = getgid ();
  1381. #if 0
  1382. uid_t euid = geteuid ();
  1383. gid_t egid = getegid ();
  1384. #endif
  1385.  
  1386.     if (perms & SYSOP_CMD)
  1387.         return (1);
  1388. #if 0
  1389.     log (-1, "ftpsecuritycheck: file - %s", filename);
  1390.     log (-1, "ftpsecuritycheck: mode - %d", mode);
  1391.     log (-1, "ftpsecuritycheck: ftpgid - %d", ACCESSgid);
  1392.     log (-1, "ftpsecuritycheck: ftpuid - %d", ACCESSuid);
  1393.     log (-1, "ftpsecuritycheck: ruid - %d", ruid);
  1394.     log (-1, "ftpsecuritycheck: rgid - %d", rgid);
  1395.     log (-1, "ftpsecuritycheck: euid - %d", euid);
  1396.     log (-1, "ftpsecuritycheck: egid - %d", egid);
  1397. #endif
  1398.     (void) setregid ((int16) ACCESSgid, (unsigned short) -1);
  1399.     (void) setreuid ((int16) ACCESSuid, (unsigned short) -1);
  1400. #if 0
  1401.     log (-1, "ftpsecuritycheck: uid - %d", getuid ());
  1402.     log (-1, "ftpsecuritycheck: gid - %d", getgid ());
  1403.     log (-1, "ftpsecuritycheck: euid - %d", geteuid ());
  1404.     log (-1, "ftpsecuritycheck: egid - %d", getegid ());
  1405. #endif
  1406.     retval = ((accval = access (filename, mode)) == 0);
  1407.  
  1408.     /* for write permissions, you can't JUST use access, if the
  1409.        file is a new file being created. */
  1410.     if (mode == W_OK && errno == 2) {
  1411.         /* if the file doesn't already exist, it takes two steps */
  1412.         if (access (filename, 0)) {
  1413.             /* first we see if the file CAN be created */
  1414.             fd = open (filename, O_CREAT | O_WRONLY | O_TRUNC);
  1415.             if (fd != -1) {
  1416.                 close (fd);
  1417.                 unlink (filename);
  1418.                 retval = 1;
  1419.             }
  1420.         }
  1421.     }
  1422.     /* now we PROBABLY know whether we can do this, but we must also
  1423.        check the directory, to see if we have write permissions, if it
  1424.        is a write
  1425.      */
  1426.     if (mode == W_OK) {
  1427.         buf = strdup (filename);
  1428.         cp = strrchr (buf, '/');
  1429.         if (cp)
  1430.             *cp = 0;
  1431.         else
  1432.             strcpy (buf, ".");
  1433.         /* set retval to whether we have write permissions to the directory */
  1434.         if (access (buf, mode))
  1435.             retval = 0;
  1436.         free (buf);
  1437.     }
  1438.     (void) setreuid (ruid, (unsigned short) -1);
  1439.     (void) setregid (rgid, (unsigned short) -1);
  1440. #if 0
  1441.     log (-1, "ftpsecuritycheck: neweuid - %d", geteuid ());
  1442.     log (-1, "ftpsecuritycheck: newegid - %d", getegid ());
  1443.     log (-1, "ftpsecuritycheck: newuid - %d", getuid ());
  1444.     log (-1, "ftpsecuritycheck: newgid - %d", getgid ());
  1445.     log (-1, "ftpsecuritycheck: accval = %d", accval);
  1446.     log (-1, "ftpsecuritycheck: retval = %d", retval);
  1447.     log (-1, "ftpsecuritycheck: errno = %d", errno);
  1448. #endif
  1449.     if (!retval)
  1450.         errno = EACCES;
  1451.     return (retval);
  1452. }
  1453. #endif
  1454.  
  1455.  
  1456.  
  1457. /* PASV mod */
  1458. static void
  1459. SendPasv (int s, struct sockaddr_in *sock)
  1460. {
  1461.     /* Send PORT a,a,a,a,p,p message */
  1462.     usprintf (s, pasvmodestr,
  1463.         hibyte (hiword (sock->sin_addr.s_addr)),
  1464.         lobyte (hiword (sock->sin_addr.s_addr)),
  1465.         hibyte (loword (sock->sin_addr.s_addr)),
  1466.         lobyte (loword (sock->sin_addr.s_addr)),
  1467.         hibyte (sock->sin_port),
  1468.         lobyte (sock->sin_port));
  1469. }
  1470.